import Facility from "../facility/Facility";
import ScoutBase from "../facility/priveteFacility/ScoutBase";
import MoveComp from "../funcComp/MoveComp";
import NodePoolManager from "../manager/NodePoolManager";
import UiManager from "../manager/UiManager";
import DestructibleFacility from "../facility/DestructibleFacility";
import DomainExpander from "../facility/priveteFacility/DomainExpander";
import MainHome from "../facility/priveteFacility/MainHome";
import GameManager from "../manager/GameManager";
import { Global } from "../info/Global";
import HowitzerBase from "../facility/priveteFacility/HowitzerBase";
import Mine from "../facility/pulbicFacility/Mine";
import OilWell from "../facility/priveteFacility/OilWell";
import RocketBase from "../facility/priveteFacility/RocketBase";
import BadgerHouse from "../facility/priveteFacility/BadgerHouse";
import ElectricBase from "../facility/priveteFacility/ElectricBase";
import IntercontinentalMissileBase from "../facility/priveteFacility/IntercontinentalMissileBase";
import NuclearBombBase from "../facility/priveteFacility/NuclearBombBase";
import FlareBase from "../facility/priveteFacility/FlareBase";
import BlackHolePredator from "../facility/priveteFacility/BlackHolePredator";
import MiningMachine from "../facility/priveteFacility/MiningMachine";
import LaunchableFalicity from "../facility/LaunchableFalicity";
import Miner from "../flyer/Other/Miner";
import { FacilityType, Gain, GamePropType, PlayerID } from "../info/GameEnum";
import ScoutReserve from "../prop/ScoutReserve";
import FlareReserve from "../prop/FlareReserve";
import { Location, MapLength, Price, blockSize } from "../info/Predefine";
import Launchable from "../funcObj/interface/Launchable";
import { Killer } from "../funcObj/interface/HealthPoint";
import MusicManager from "../../MusicManager";
import PLayerDestructibleFlyer from "../flyer/Other/PLayerDestructibleFlyer";

const { ccclass, property } = cc._decorator;

@ccclass
export default abstract class Player extends cc.Component {


    public static readonly EventType = {
        安家: "安家", //安家
        基地被摧毁: "基地被摧毁",
        摧毁敌人基地: "摧毁敌人基地",
        找到新的对手: "找到新的对手",//找到新的对手
        更新晶石: "更新晶石",//更新晶石
        更新石油: "更新石油",//更新石油
        更新基地等级: "更新基地等级",
        更新矿工采矿数量等级: "更新矿工采矿数量等级",
        更新矿工速度等级: "更新矿工速度等级",
        更新飞行物数量: "更新飞行物数量",
        被设定为目标: "被设定为目标",
        我的设施被攻击: "我的设施被攻击",
        我的飞行物被攻击: "我的飞行物被攻击",
        击毁敌方飞行物: "击毁敌方飞行物",
        被发现: "被发现"
    }

    /**
     * 角色id
     */
    roleId: number;

    /**
     * 记录玩家下的设施
     */
    facilityArr: DestructibleFacility[][];

    /**
     * 已发现的敌方玩家
     * 获得视野时push
     */
    discoveredEnemy: Player[]

    private _diamond: number;
    private _oil: number;

    //级别
    private _miningCountLevel: number;
    private _minerSpeedLevel: number;
    private _shellDamageBonusLevel = 0;
    private _shellHealthBonusLevel = 0;
    private _shellRangeBonusLevel = 0;
    private _buildingHealthLevel = 0;
    private _buildingDefenseLevel = 0;
    private _artilleryDamageBonusLevel = 0;


    domainArr: Location[];

    /**
     * 记录各项功能冷却时间
     * key: 功能类型
     * value: 冷却时间 单位 秒
     */
    coolDownMap: Map<string, number> = new Map();

    /**
     * 颜色
     */
    public get playerId(): PlayerID {
        return Global.getPlayerId(this.roleId);
    }

    /**
     * 显示的名字
     */
    public get playerName(): string {
        return Global.currentGameData.enemy[this.playerId].nikeName;
    }

    /**
     * 所有设施
     */
    public get allFacility(): DestructibleFacility[] {
        return this.facilityArr.flat();
    }

    /**
     * 额外视野,获得视野时多获得一点
     */
    public get extraView(): number {
        let result = 0;
        if (this.props[GamePropType.鹰眼]) {
            result += 1;
        }
        return result;
    }

    /**
     * 矿工招募价格
     */
    public get minerPrice(): Price {
        let price = Global.FacilityInfo[FacilityType.主基地].矿工招募要求;
        let result = { diamond: price.diamond, oil: price.oil };
        if (this.props[GamePropType.便宜矿工]) {
            result.diamond = Math.ceil(result.diamond * 0.5);
            result.oil = Math.ceil(result.oil * 0.5);
        }
        return result;
    }

    /**
     * 矿工采矿数量
     */
    public get miningCount(): number {
        // 精炼
        let result = Global.baseMiningCount + Global.FacilityInfo[FacilityType.主基地].采矿数量.每等级加成[this.miningCountLevel]
        if (this.props[GamePropType.精炼]) {
            result = Math.ceil(result * 1.5);
        }
        return result;
    }

    /**
     * 返回所有矿工
     */
    public get allMiner(): Miner[] {
        let result: Miner[] = [];
        result.concat((<MainHome>this.facilityArr[FacilityType.主基地][0]).minerArr)
        this.facilityArr[FacilityType.矿机].forEach((fac: MiningMachine) => result.concat(fac.minerArr))
        return result;
    }

    /**
     * 主基地等级
     */
    get mainHomeLevel() {
        return this.facilityArr[FacilityType.主基地][0].level;
    }


    /**
     * 玩家下的矿工采矿数量等级
     */
    get miningCountLevel() {
        return this._miningCountLevel
    }
    set miningCountLevel(val: number) {
        this._miningCountLevel = val
        this.node.emit(Player.EventType.更新矿工采矿数量等级, this._miningCountLevel);
    }

    /**
     * 矿工移动速度等级
     */
    get minerSpeedLevel() {
        return this._minerSpeedLevel
    }
    set minerSpeedLevel(val: number) {
        this._minerSpeedLevel = val
        this.node.emit(Player.EventType.更新矿工速度等级, this._minerSpeedLevel);
    }

    /**
     * 炮弹伤害加成等级
     */
    public get shellDamageBonusLevel(): number {
        return this._shellDamageBonusLevel;
    }
    public set shellDamageBonusLevel(v: number) {
        this._shellDamageBonusLevel = v;
    }

    /**
    * 炮弹血量加成等级
    */
    public get shellHealthBonusLevel(): number {
        return this._shellHealthBonusLevel;
    }
    public set shellHealthBonusLevel(v: number) {
        this._shellHealthBonusLevel = v;
    }

    /**
    * 炮弹射程加成等级
    */
    public get shellRangeBonusLevel(): number {
        return this._shellRangeBonusLevel;
    }
    public set shellRangeBonusLevel(v: number) {
        this._shellRangeBonusLevel = v;
    }

    /**
    * 设施建筑血量加成等级
    */
    public get buildingHealthLevel(): number {
        return this._buildingHealthLevel;
    }
    public set buildingHealthLevel(v: number) {
        this._buildingHealthLevel = v;
    }

    /**
    * 设施建筑防御加成等级
    */
    public get buildingDefenseLevel(): number {
        return this._buildingDefenseLevel;
    }
    public set buildingDefenseLevel(v: number) {
        this._buildingDefenseLevel = v;
    }

    /**
    * 近防炮攻击加成等级
    */
    public get artilleryDamageBonusLevel(): number {
        return this._artilleryDamageBonusLevel;
    }
    public set artilleryDamageBonusLevel(v: number) {
        this._artilleryDamageBonusLevel = v;
    }

    /**
     * 晶石数量
     */
    public get diamond(): number {
        return this._diamond
    }
    public set diamond(v: number) {
        this._diamond = v;
        this.node.emit(Player.EventType.更新晶石, this._diamond);
    }
    /**
     * 石油数量
     */
    public get oil(): number {
        return this._oil
    }
    public set oil(v: number) {
        this._oil = v;
        this.node.emit(Player.EventType.更新石油, this._oil);
    }

    /**
     * 侦察机数量
     */
    public get scoutCount(): number {
        let ret = 0;
        this.facilityArr[FacilityType.侦察机基地].forEach((item: ScoutBase) => {
            ret += item.count;
        })
        let sr = this.facilityArr[FacilityType.主基地][0].getComponentInChildren(ScoutReserve);
        if (sr) {
            ret += sr.count;
        }
        return ret;
    }

    /**
     * 榴弹数量
     */
    public get howitzerCount(): number {
        let ret = 0;
        this.facilityArr[FacilityType.榴弹炮基地].forEach((item: HowitzerBase) => {
            ret += item.howitzerCount;
        })
        return ret;
    }

    /**
     * 火箭炮数量
     */
    public get rocketCount(): number {
        let ret = 0;
        this.facilityArr[FacilityType.火箭炮基地].forEach((item: RocketBase) => {
            ret += item.rocketQueue.length;
        })
        return ret;
    }

    /**
     * 电磁炮数量
     */
    public get electricCount(): number {
        let ret = 0;
        this.facilityArr[FacilityType.电磁炮基地].forEach((item: ElectricBase) => {
            ret += item.electricCount;
        })
        return ret;
    }

    /**
     * 照明弹数量
     */
    public get flareCount(): number {
        let ret = 0;
        this.facilityArr[FacilityType.照明弹基地].forEach((item: FlareBase) => {
            ret += item.count;
        })
        let fr = this.facilityArr[FacilityType.主基地][0].getComponentInChildren(FlareReserve);
        if (fr) {
            ret += fr.count;
        }
        return ret;
    }

    /**
     * 洲际导弹数量
     */
    public get intercontinentalMissileCount(): number {
        let ret = 0;
        this.facilityArr[FacilityType.洲际导弹基地].forEach((item: IntercontinentalMissileBase) => {
            ret += item.intercontinentalMissileQueue.length;
        })
        return ret;
    }

    /**
     * 核弹数量
     */
    public get nuclearBombCount(): number {
        let ret = 0;
        this.facilityArr[FacilityType.核弹基地].forEach((item: NuclearBombBase) => {
            ret += item.nuclearBombCount;
        })
        return ret;
    }

    /**
     * 黑洞掠夺者数量
     */
    public get blackHoleCount(): number {
        let ret = 0;
        this.facilityArr[FacilityType.黑洞掠夺者].forEach((item: BlackHolePredator) => {
            ret += item.blackHoleQueue.length;
        })
        return ret;
    }

    /**
     * 平头哥数量
     */
    public get badgerCount(): number {
        let ret = 0;
        this.facilityArr[FacilityType.平头哥之家].forEach((item: BadgerHouse) => {
            ret += item.badgerCount;
        })
        return ret;
    }

    /**
     * 设置是否看到所有地图
     */
    public abstract set showAllView(v: boolean);

    /**
     * 飞行物父节点
     */
    public abstract get flyerParentNode(): cc.Node;

    public abstract get flyerhpColor(): cc.SpriteFrame;

    public abstract get facilityHpColor(): cc.SpriteFrame;


    /**
     * 玩家身上的道具
     */
    props: GamePropType[];

    addDiamond(value: number, ...args: any[])
    addDiamond(value: number) {
        this.diamond += value;
    }

    addOil(value: number, ...args: any[])
    addOil(value: number) {
        this.oil += value;
    }

    addDiamondAndOil(diamond: any, oil: any, position?: cc.Vec3) {
        this.diamond += diamond;
        this.oil += oil;
    }

    /**
     * 按设施类型获取
     * @param facilitytype 
     * @returns 
     */
    getAllFlyerCountByFacilityType(facilitytype: FacilityType) {
        let ret = 0;
        this.facilityArr[facilitytype].forEach((item: LaunchableFalicity) => {
            ret += item.count;
        })
        if (facilitytype == FacilityType.侦察机基地) {
            let sr = this.facilityArr[FacilityType.主基地][0].getComponentInChildren(ScoutReserve)
            if (sr) {
                ret += sr.count;
            }
        }
        if (facilitytype == FacilityType.照明弹基地) {
            let fr = this.facilityArr[FacilityType.主基地][0].getComponentInChildren(FlareReserve)
            if (fr) {
                ret += fr.count;
            }
        }
        return ret;
    }

    /**
     * 基地升级
     */
    MainHomeLevelUp() {
        this.facilityArr[FacilityType.主基地][0].levelUp();
    }

    /**
     * 采矿数量升级
     */
    miningCountLevelUp() {
        let price = Global.FacilityInfo[FacilityType.主基地].采矿数量.每等级升级要求[this.miningCountLevel];
        this.miningCountLevel++;
        this.diamond -= price.diamond;
        this.oil -= price.oil;
    }

    /**
     * 采矿速度升级
     */
    miningSpeedLevelUp() {
        let price = Global.FacilityInfo[FacilityType.主基地].矿工速度.每等级升级要求[this.minerSpeedLevel];
        this.minerSpeedLevel++;
        this.diamond -= price.diamond;
        this.oil -= price.oil;
    }

    /**
     * 炮弹血量升级
     */
    shellHealthBonusLevelUp() {
        let price = Global.FacilityInfo[FacilityType.主基地].炮弹血量.每等级升级要求[this.shellHealthBonusLevel];
        this.shellHealthBonusLevel++;
        this.diamond -= price.diamond;
        this.oil -= price.oil;
    }

    /**
     * 建筑血量升级
     */
    buildingHealthLevelUp() {
        let price = Global.FacilityInfo[FacilityType.主基地].建筑血量.每等级升级要求[this.buildingHealthLevel];
        this.buildingHealthLevel++;
        this.diamond -= price.diamond;
        this.oil -= price.oil;

        //按比例恢复所有设施血量
        this.allFacility.forEach((itme: DestructibleFacility) => {
            let hpRate = itme.currentHp / itme.maxHp;
            itme.initHp();
            itme.currentHp = 0;
            itme.repairHp(Math.ceil(itme.maxHp * hpRate));
        })

    }

    /**
    * 炮弹攻击升级
    */
    shellDamageBonusLevelUp() {
        let price = Global.FacilityInfo[FacilityType.主基地].炮弹攻击.每等级升级要求[this.shellDamageBonusLevel];
        this.shellDamageBonusLevel++;
        this.diamond -= price.diamond;
        this.oil -= price.oil;
    }

    /**
     * 炮弹射程升级
     */
    shellRangeBonusLevelUp() {
        let price = Global.FacilityInfo[FacilityType.主基地].炮弹射程.每等级升级要求[this.shellRangeBonusLevel];
        this.shellRangeBonusLevel++;
        this.diamond -= price.diamond;
        this.oil -= price.oil;
    }

    /**
     *  建筑防御升级
     */
    buildingDefenseLevelUp() {
        let price = Global.FacilityInfo[FacilityType.主基地].建筑防御.每等级升级要求[this.buildingDefenseLevel];
        this.buildingDefenseLevel++;
        this.diamond -= price.diamond;
        this.oil -= price.oil;
    }

    /**
     * 近防炮攻击升级
     */
    artilleryDamageBonusLevelUp() {
        let price = Global.FacilityInfo[FacilityType.主基地].近防炮攻击.每等级升级要求[this.artilleryDamageBonusLevel];
        this.artilleryDamageBonusLevel++;
        this.diamond -= price.diamond;
        this.oil -= price.oil;
    }

    /**
     * 修理基地
     */
    repairMainhome() {
        let price = Global.FacilityInfo[FacilityType.主基地].维修基地.维修要求;
        let mainHome: MainHome = <MainHome>this.facilityArr[FacilityType.主基地][0];
        mainHome.repairHp(mainHome.maxHp / 2);
        this.diamond -= price.diamond;
        this.oil -= price.oil;

        this.coolDownMap.set("维修基地", 60);
    }

    protected start() {
        // 初始化设施数组
        this.facilityArr = [];
        for (const key of Object.keys(FacilityType)) this.facilityArr[FacilityType[key]] = [];

        //钻矿石和油矿
        this.diamond = 0;
        this.oil = 0;

        //矿工挖矿数量级别
        this.miningCountLevel = 0;
        //矿工移动速度级别
        this.minerSpeedLevel = 0;

        //已发现的敌方玩家
        this.discoveredEnemy = [];

        this.diamond = 50;

        this.domainArr = [];

        //初始视野
        let location = GameManager.instance.getMapLocation(this.node.position);

        let leftUp = { locationX: Math.max(0, location.locationX - 1), locationY: Math.max(0, location.locationY - 1) };
        let rightDown = { locationX: Math.min(MapLength - 1, location.locationX + 1), locationY: Math.min(MapLength - 1, location.locationY + 1) };
        for (let i = leftUp.locationX; i <= rightDown.locationX; i++) {
            for (let j = leftUp.locationY; j <= rightDown.locationY; j++) {
                this.getLocationView({ locationX: i, locationY: j })
            }
        }
    }

    public init(roleId: number, props: GamePropType[]) {
        this.roleId = roleId;
        this.props = props;
        //监听玩家安家事件
        this.node.on(Player.EventType.安家, this.onOtherMakeHome, this);
        this.node.on(Player.EventType.摧毁敌人基地, this.onKillOtherPlayer, this);
    }

    /**
     * 安家
     */
    public makeHome(): boolean {
        let mainHome = GameManager.instance.addMainHome(this);
        if (!mainHome) {
            UiManager.instance.showTip("这里没有空间了！");
            return false;
        }
        this.facilityArr[mainHome.facilityType] = [mainHome];
        //移除显示的人物
        //清除资源
        //移除moveComp
        cc.assetManager.releaseAsset(this.getComponentInChildren(cc.Animation).getClips()[0]);
        this.node.removeAllChildren();
        this.getComponent(MoveComp).destroy();
        this.getComponent(PLayerDestructibleFlyer).destroy();
        //玩家建立基地后，隐藏所有安家点
        this.node.emit(Player.EventType.安家, this);
        this.node.off(Player.EventType.安家);

        mainHome.init(this);
        return true;
    }

    /**
   * 添加一个设施到玩家的设施列表中
   * @param facilityType - 设施的类型，使用枚举 FacilityType 表示
   * @param locaitons - 设施要放置的位置数组，每个位置为 Location 类型
   * @param price - 设施的建造价格，包含晶矿和石油的数量，默认为该设施的当前建造价格
   * @returns 添加成功的设施组件，类型为 DestructibleFacility
   */
    public addFacility(facilityType: FacilityType, locaitons: Location[], price: { diamond: number, oil: number } = this.getPrice(facilityType)): DestructibleFacility {
        // 如果设施类型为采油机，则调用专门的方法添加采油机设施
        if (facilityType == FacilityType.采油机)
            return this.addOilWellFacility(GameManager.instance.getFacilityByLocation(locaitons[0]) as Mine);

        // 扣除建造设施所需的晶矿和石油
        this.diamond -= price.diamond;
        this.oil -= price.oil;
        // 从对象池中获取对应类型设施的节点
        let facility = NodePoolManager.instance.obtain(NodePoolManager.instance.getPrefabByFacilityType(facilityType));
        // 获取设施节点上的可破坏设施组件
        let comp = facility.getComponent(DestructibleFacility);
        // 将设施节点添加到游戏管理的设施父节点下
        facility.parent = GameManager.instance.facilityParent;
        // 初始化设施的最终位置
        let finalPosition = cc.v3(0, 0);
        // 遍历设施要放置的位置数组
        for (let i = 0; i < locaitons.length; i++) {
            // 累加每个位置的游戏坐标到最终位置
            finalPosition.addSelf(GameManager.instance.getGamePosition(locaitons[i]));
            // 在游戏管理的设施地图数组中设置该设施的位置信息
            GameManager.instance.setFacilityMapArray(comp, locaitons[i]);
        }
        // 计算设施的平均位置作为最终位置
        finalPosition.divSelf(locaitons.length);
        // 设置设施节点的位置
        facility.position = finalPosition;
        // 设置设施节点的 zIndex，根据第一个位置的 y 坐标确定
        facility.zIndex = locaitons[0].locationY;
        // 将设施组件添加到玩家的设施数组中
        this.facilityArr[facilityType].push(comp);
        // 设置设施的建造价格
        comp.price = price;
        // 设置设施的位置信息
        comp.locations = locaitons;
        // 初始化设施组件
        comp.init(this);
        // 播放设施建造的音效
        MusicManager.instance.play(MusicManager.instance.build_build, this.node);
        // 返回添加成功的设施组件
        return comp;
    }

    /**
     * 在油矿上添加一个采油机
     * @param mine 
     * @param price 
     */
    private addOilWellFacility(mine: Mine, price: { diamond: number, oil: number } = this.getPrice(FacilityType.采油机)): OilWell {
        this.diamond -= price.diamond;
        this.oil -= price.oil;

        let mineWell = mine.getComponent(OilWell);
        let locations = GameManager.instance.getMapLocation(mineWell.node.position);
        mineWell.init(this);
        mineWell.locations = [locations];
        mineWell.price = price;
        this.facilityArr[FacilityType.采油机].push(mineWell);
        GameManager.instance.setFacilityMapArray(mineWell, locations, false);
        return mineWell;
    }

    /**
     * 发射指定类型的飞弹
     * 返回发射的基地
     * @param type 
     * @param target 
     * @returns 
     */
    dispatchFlyer(type: FacilityType, target: Location): DestructibleFacility {
        let list: Launchable[] = this.facilityArr[type].concat() as LaunchableFalicity[];
        if (type == FacilityType.侦察机基地) {
            let sr = this.facilityArr[FacilityType.主基地][0].getComponentInChildren(ScoutReserve)
            if (sr) {
                list.push(sr);
            }
        }
        if (type == FacilityType.照明弹基地) {
            let fr = this.facilityArr[FacilityType.主基地][0].getComponentInChildren(FlareReserve)
            if (fr) {
                list.push(fr);
            }
        }

        let base: LaunchableFalicity = list.find((item: LaunchableFalicity) => {
            let disX = Math.abs(target.locationX - item.locations[0].locationX),
                disY = Math.abs(target.locationY - item.locations[0].locationY)
            let distance = Math.round(Math.sqrt(disX * disX + disY * disY));
            return item.count > 0 && item.shotRange >= distance
        }) as LaunchableFalicity;

        if (base) {
            base.dispatch(target);
            return base;
        } else {
            return null;
        }
    }

    /**
     * 当前所有地盘
     */
    getDomainArr(): Location[] {
        let result = [];
        for (let i = 0; i < this.facilityArr[FacilityType.主基地].length; i++) {
            let main = this.facilityArr[FacilityType.主基地][i] as MainHome
            result = result.concat(main.myDomain);
        }

        for (let i = 0; i < this.facilityArr[FacilityType.领土扩张器].length; i++) {
            let expander = this.facilityArr[FacilityType.领土扩张器][i] as DomainExpander
            result = result.concat(expander.myDomain);
        }
        return result;
    }


    /**
     * 得到新地盘
     */
    public onGetNewDomain(newDomain: Location[]) {
        this.domainArr = this.getDomainArr();
    }

    /**
    * 失去领地
    * @param domain 
    */
    public loseDomain(domain: Location[]) {
        this.domainArr = this.getDomainArr();
    }

    /**
     * 检查传入的位置是否是自己的领地
     * @param location 
     * @returns 
     */
    public isSelfDomain(location: Location): boolean {
        return !!this.domainArr.find(domain => domain.locationX == location.locationX && domain.locationY == location.locationY)
    }

    /**
     * 检查位置是否可以被使用 建设设施
     * @param location 
     * @returns 
     */
    public canBeUesd(location: Location) {
        if (location.locationX >= 0 && location.locationX < MapLength && location.locationY >= 0 && location.locationY < MapLength) {
            let fac = GameManager.instance.getFacilityByLocation(location);
            return (!fac || fac.facilityType == FacilityType.安家点) && this.isSelfDomain(location);
        }
        return false;
    }

    /**
     * 检查价格是否足够购买
     * @param price 
     * @returns 
     */
    public checkEnoughMoney(price: { diamond: number, oil: number }): boolean {
        return this.diamond >= price.diamond && this.oil >= price.oil;
    }

    /**
     * 检查建造设施所有条件是否达成
     * 晶矿够不够
     * 油矿够不够
     * 是否解锁
     * 建造上限
     * @param facilityType 
     * @returns 
     */
    public checkFacilityCondition(facilityType: FacilityType): boolean[] {
        let facilityInfo = Global.getFacilityInfo<{ 建造价格: { diamond: number, oil: number }, 每数量增加价格: { diamond: number, oil: number }, 解锁等级: number, 每主基地等级可建造上限: number[] }>(facilityType);
        let basePrice = facilityInfo.建造价格;
        let rise = facilityInfo.每数量增加价格;
        let unLockLevel = facilityInfo.解锁等级;
        let buildLimit = facilityInfo.每主基地等级可建造上限[this.mainHomeLevel];
        let priceDiamond = basePrice.diamond + rise.diamond * this.facilityArr[facilityType].length;
        let priceOil = basePrice.oil + rise.oil * this.facilityArr[facilityType].length;
        let ret = [];

        if (facilityType == FacilityType.领土扩张器 && this.props[GamePropType.旗帜上限]) {
            buildLimit += 2;
        }

        ret.push(this.diamond >= priceDiamond);
        ret.push(this.oil >= priceOil);
        ret.push(this.mainHomeLevel + 1 >= unLockLevel);
        ret.push(this.facilityArr[facilityType].length < buildLimit);
        return ret;
    }

    /**
     * 检查购买增益的所有条件是否达成
     * 晶矿
     * 油矿
     * 是否解锁
     * 达到上限
     */
    public checkGainCondition(gain: Gain): boolean[] {
        let result: boolean[] = [];
        let mainHomeInfo = Global.FacilityInfo[FacilityType.主基地];
        let unlockLevel = 0;
        switch (gain) {
            case Gain.招募矿工:
                let minerPrice = this.minerPrice;
                result[0] = this.diamond >= minerPrice.diamond;
                result[1] = this.oil >= minerPrice.oil;
                result[2] = !0;
                result[3] = (<MainHome>this.facilityArr[FacilityType.主基地][0]).minerArr.length < mainHomeInfo.每基地等级招募矿工上限[Math.min(this.mainHomeLevel, mainHomeInfo.每基地等级招募矿工上限.length - 1)]
                break;
            case Gain.升级主基地:
                result[3] = !!mainHomeInfo.每等级升级要求[this.mainHomeLevel];
                result[2] = !0;
                if (result[3]) {
                    result[0] = this.diamond >= mainHomeInfo.每等级升级要求[this.mainHomeLevel].diamond;
                    result[1] = this.oil >= mainHomeInfo.每等级升级要求[this.mainHomeLevel].oil;
                } else {
                    result[0] = !0;
                    result[1] = !0;
                }
                break;
            case Gain.建筑血量升级:
                result[3] = !!mainHomeInfo.建筑血量.每等级升级要求[this.buildingHealthLevel];
                if (result[3]) {
                    unlockLevel = mainHomeInfo.建筑血量.每等级升级要求[this.buildingHealthLevel].level;
                    result[0] = this.diamond >= mainHomeInfo.建筑血量.每等级升级要求[this.buildingHealthLevel].diamond;
                    result[1] = this.oil >= mainHomeInfo.建筑血量.每等级升级要求[this.buildingHealthLevel].oil;
                    result[2] = this.mainHomeLevel + 1 >= unlockLevel;
                } else {
                    result[0] = true;
                    result[1] = true;
                    result[2] = true;
                }
                break;
            case Gain.建筑防御升级:
                result[3] = !!mainHomeInfo.建筑防御.每等级升级要求[this.buildingDefenseLevel];
                if (result[3]) {
                    unlockLevel = mainHomeInfo.建筑防御.每等级升级要求[this.buildingDefenseLevel].level;
                    result[0] = this.diamond >= mainHomeInfo.建筑防御.每等级升级要求[this.buildingDefenseLevel].diamond;
                    result[1] = this.oil >= mainHomeInfo.建筑防御.每等级升级要求[this.buildingDefenseLevel].oil;
                    result[2] = this.mainHomeLevel + 1 >= unlockLevel;
                } else {
                    result[0] = true;
                    result[1] = true;
                    result[2] = true;
                }
                break;
            case Gain.炮弹射程升级:
                result[3] = !!mainHomeInfo.炮弹射程.每等级升级要求[this.buildingDefenseLevel];
                if (result[3]) {
                    unlockLevel = mainHomeInfo.炮弹射程.每等级升级要求[this.shellRangeBonusLevel].level;
                    result[0] = this.diamond >= mainHomeInfo.炮弹射程.每等级升级要求[this.shellRangeBonusLevel].diamond;
                    result[1] = this.oil >= mainHomeInfo.炮弹射程.每等级升级要求[this.shellRangeBonusLevel].oil;
                    result[2] = this.mainHomeLevel + 1 >= unlockLevel;
                } else {
                    result[0] = true;
                    result[1] = true;
                    result[2] = true;
                }
                break;
            case Gain.炮弹攻击力升级:
                result[3] = !!mainHomeInfo.炮弹攻击.每等级升级要求[this.shellDamageBonusLevel];
                if (result[3]) {
                    unlockLevel = mainHomeInfo.炮弹攻击.每等级升级要求[this.shellDamageBonusLevel].level;
                    result[0] = this.diamond >= mainHomeInfo.炮弹攻击.每等级升级要求[this.shellDamageBonusLevel].diamond;
                    result[1] = this.oil >= mainHomeInfo.炮弹攻击.每等级升级要求[this.shellDamageBonusLevel].oil;
                    result[2] = this.mainHomeLevel + 1 >= unlockLevel;
                } else {
                    result[0] = true;
                    result[1] = true;
                    result[2] = true;
                }
                break;
            case Gain.炮弹血量升级:
                result[3] = !!mainHomeInfo.炮弹血量.每等级升级要求[this.shellHealthBonusLevel];
                if (result[3]) {
                    unlockLevel = mainHomeInfo.炮弹血量.每等级升级要求[this.shellHealthBonusLevel].level;
                    result[0] = this.diamond >= mainHomeInfo.炮弹血量.每等级升级要求[this.shellHealthBonusLevel].diamond;
                    result[1] = this.oil >= mainHomeInfo.炮弹血量.每等级升级要求[this.shellHealthBonusLevel].oil;
                    result[2] = this.mainHomeLevel + 1 >= unlockLevel;
                } else {
                    result[0] = true;
                    result[1] = true;
                    result[2] = true;
                }
                break;
            case Gain.维修基地:
                result[0] = this.diamond >= mainHomeInfo.维修基地.维修要求.diamond;
                result[1] = this.oil >= mainHomeInfo.维修基地.维修要求.oil;
                unlockLevel = mainHomeInfo.维修基地.维修要求.level
                result[2] = this.mainHomeLevel + 1 >= unlockLevel;
                result[3] = !!this.coolDownMap.get("维修基地");
                break;
            case Gain.近防炮攻击升级:
                result[3] = !!mainHomeInfo.近防炮攻击.每等级升级要求[this.artilleryDamageBonusLevel];
                if (result[3]) {
                    unlockLevel = mainHomeInfo.近防炮攻击.每等级升级要求[this.artilleryDamageBonusLevel].level;
                    result[0] = this.diamond >= mainHomeInfo.近防炮攻击.每等级升级要求[this.artilleryDamageBonusLevel].diamond;
                    result[1] = this.oil >= mainHomeInfo.近防炮攻击.每等级升级要求[this.artilleryDamageBonusLevel].oil;
                    result[2] = this.mainHomeLevel + 1 >= unlockLevel;
                } else {
                    result[0] = true;
                    result[1] = true;
                    result[2] = true;
                }
                break;
            case Gain.采矿数量升级:
                result[3] = !!mainHomeInfo.采矿数量.每等级升级要求[this.miningCountLevel];
                if (result[3]) {
                    unlockLevel = mainHomeInfo.采矿数量.每等级升级要求[this.miningCountLevel].level;
                    result[0] = this.diamond >= mainHomeInfo.采矿数量.每等级升级要求[this.miningCountLevel].diamond;
                    result[1] = this.oil >= mainHomeInfo.采矿数量.每等级升级要求[this.miningCountLevel].oil;
                    result[2] = this.mainHomeLevel + 1 >= unlockLevel;
                } else {
                    result[0] = true;
                    result[1] = true;
                    result[2] = true;
                }
                break;
            case Gain.采矿速度升级:
                result[3] = !!mainHomeInfo.矿工速度.每等级升级要求[this.minerSpeedLevel];
                if (result[3]) {
                    unlockLevel = mainHomeInfo.矿工速度.每等级升级要求[this.minerSpeedLevel].level;
                    result[0] = this.diamond >= mainHomeInfo.矿工速度.每等级升级要求[this.minerSpeedLevel].diamond;
                    result[1] = this.oil >= mainHomeInfo.矿工速度.每等级升级要求[this.minerSpeedLevel].oil;
                    result[2] = this.mainHomeLevel + 1 >= unlockLevel;
                } else {
                    result[0] = true;
                    result[1] = true;
                    result[2] = true;
                }
                break;
        }
        return result;
    }

    /**
     * 获取设施的建造价格
     * @param facilityType 
     * @returns 
     */
    public getPrice(facilityType: FacilityType): { diamond: number, oil: number } {
        let facilityInfo = Global.getFacilityInfo<{ 建造价格: { diamond: number, oil: number }, 每数量增加价格: { diamond: number, oil: number } }>(facilityType);
        let basePrice = facilityInfo.建造价格;
        let rise = facilityInfo.每数量增加价格;
        return { diamond: basePrice.diamond + rise.diamond * this.facilityArr[facilityType].length, oil: basePrice.oil + rise.oil * this.facilityArr[facilityType].length };
    }


    /**
     * 传入设施所需的位置大小
     * 获取所有符合条件的空地
     * @param height 
     * @param width 
     */
    public getSpaceBySize(size: number): Location[][] {
        let result: Location[][] = [];
        //获得所有空地
        let allSpace = this.domainArr.filter(location => this.canBeUesd(location));
        switch (size) {
            case 1:
                result = allSpace.map(location => [location])
                break;
            case 2: // 1*2大小
                allSpace.forEach(location => {
                    let up = { locationX: location.locationX, locationY: location.locationY - 1 };
                    if (this.canBeUesd(up)) {
                        result.push([location, up]);
                    }
                })
                break;
            case 3:// 1*3大小
                allSpace.forEach(location => {
                    let up1 = { locationX: location.locationX, locationY: location.locationY - 1 };
                    let up2 = { locationX: location.locationX, locationY: location.locationY - 2 };
                    if (this.canBeUesd(up1) && this.canBeUesd(up2)) {
                        result.push([location, up1, up2]);
                    }
                })
                break;
            case 4: // 2*2大小
                allSpace.forEach(location => {
                    let up = { locationX: location.locationX, locationY: location.locationY - 1 };

                    let left = { locationX: location.locationX - 1, locationY: location.locationY };

                    let upLeft = { locationX: location.locationX - 1, locationY: location.locationY - 1 };
                    if (this.canBeUesd(up) && this.canBeUesd(left) && this.canBeUesd(upLeft)) {
                        result.push([location, up, left, upLeft]);
                    }
                })
                break;
        }
        return result;
    }


    /**
     * 玩家死亡处理方法，当玩家被击败时调用此方法
     * @param killer - 击杀者信息，包含击杀者的相关数据
     */
    public die(killer: Killer) {
        // 隐藏玩家节点，使其在游戏中不可见
        this.node.active = false;
        // 遍历玩家所有的设施，调用每个设施的 die 方法，标记设施被摧毁
        this.allFacility.forEach(fac => fac.die(killer));
        // 将当前玩家添加到全局游戏数据的死亡排行榜中
        Global.currentGameData.deathRank.push(this);

        // 向击杀者玩家节点发送事件，通知其成功摧毁敌人基地
        killer.player.node.emit(Player.EventType.摧毁敌人基地, this);
        // 向当前玩家节点发送事件，通知其基地已被摧毁
        this.node.emit(Player.EventType.基地被摧毁, killer, this);
        // 移除当前玩家节点上关于摧毁敌人基地事件的监听
        this.node.off(Player.EventType.摧毁敌人基地);
        // 移除当前玩家节点上关于基地被摧毁事件的监听
        this.node.off(Player.EventType.基地被摧毁);
        // 播放玩家被击杀的音效
        MusicManager.instance.play(MusicManager.instance.kill_Player);
    };

    /**
     * 当其他玩家安家
     *  判断是否在自己的视野内
     */
    private onOtherMakeHome(otherPlayer: Player) {
        if (otherPlayer !== this) {
            if (!this.discoveredEnemy.includes(otherPlayer))
                if (this.isFacilityVisible(otherPlayer.facilityArr[FacilityType.主基地][0])) {
                    this.discoveredEnemy.push(otherPlayer);
                    this.onFindNewEnemy(otherPlayer);
                }
        }
    }

    /**
     * 摧毁其他玩家的基地
     */
    protected onKillOtherPlayer() {
        this.addDiamondAndOil(Global.KillBonus.diamond, Global.KillBonus.oil);
    }

    /**
     * 发现新敌人
     * @param player 
     */
    protected abstract onFindNewEnemy(player: Player): void

    /**
    * 获取这个位置的视野
    */
    public abstract getLocationView(location: Location): void

    /**
     * 检查位置是否可见
     */
    public abstract isLocationVisible(location: Location): boolean;

    /**
     * 检查设施是否可见
     * @param location 
     */
    public abstract isFacilityVisible(location: Facility): boolean;

    protected update(dt: number): void {
        if (this.coolDownMap.size > 0) {
            this.coolDownMap.forEach((value, key) => {
                let step = value - dt;
                if (step <= 0) {
                    this.coolDownMap.delete(key);
                } else {
                    this.coolDownMap.set(key, value - dt);
                }
            })
        }
    }
}
